<script setup>
import {
    computed,
    getCurrentInstance,
    nextTick,
    onMounted,
    provide,
    reactive,
    ref, watch
} from 'vue'
import { Icons, pageSizeOptions } from '@/constants'
import { JBoltApi } from '@/service/request'
import { NSpin, NModal, NCard, NSpace, NPagination } from 'naive-ui'
import JbIcon from '@/components/_builtin/jb-icon/index.vue'
import JbBtn from '@/components/_builtin/jb-btn/index.vue'


const props = defineProps({
    /** 条件区域元素排列方式 */
    conditionsAlign: {
        type: String,
        default: 'center',
        validator: (value) => ['start', 'end', 'center', 'space-around', 'space-between', 'space-evenly'].includes(value)
    },
    /** 是否整个区域显示边框 */
    bordered: {
        type: Boolean,
        default: false
    },
    /** 是否显示header部分 */
    headerShown: {
        type: Boolean,
        default: true
    },
    /**title区域显示的图标*/
    titleIcon: String,
    /**
     * title区域显示的文本
     */
    titleText: String,
    /**查询地址，传入就会自动执行查询*/
    searchUrl: String,
    /**查询条件*/
    searchConditions: Object,
    /** 插槽自带的搜索按钮是否 显示 */
    searchBtnShown: {
        type: Boolean,
        default: true
    },
    /** 插槽自带的重置按钮是否 显示 */
    resetBtnShown: {
        type: Boolean,
        default: true
    },
    /**是否分页*/
    pager: {
        type: Boolean,
        default: true
    },
    /**编辑组件*/
    editComponent: Object,
    /**编辑弹窗宽度*/
    editModalWidth: String,
    /** 排序字段对应的参数名 */
    sortColumnFieldName: {
        type: String,
        default: 'sortColumn'
    },
    /** 排序类型对应的参数名 */
    sortTypeFieldName: {
        type: String,
        default: 'sortType'
    }
})

const emit = defineEmits([
    'afterSubmit',
    'beforeSearch',
    'afterSearch',
    'afterRender'
])

/*    查询相关start    */

/** 页面相关数据 */
const state = reactive({
    searching: false, //当前是否正在查询中
    list: [], //当前查询到的数据列表
    sortSet: [], //排序设置
    pager: {
        page: 1,
        pageSize: 20,
        totalRow: 0
    },
    editModalShown: false, //是否显示编辑弹窗
    isSubmiting: false, //是否正在提交
    editingProps: {}, //当前正在编辑的条目的其他参数
    editModalArgs: {}, //编辑弹出框的参数
    tableStartIndex: 0 //表格初始索引值
})

/** 加载数据 */
async function loadData(resetPage) {
    if (!props.searchUrl) return
    if (state.searching) return
    emit('beforeSearch')
    if (resetPage) {
        state.pager.page = 1
    }
    state.searching = true
    try {
        let conditions = {}
        if (props.searchConditions) {
            conditions = { ...props.searchConditions }
        }
        if (state.sortSet.length) {
            //todo 目前只支持一列排序
            conditions[props.sortColumnFieldName] = state.sortSet[0].sortColumn
            conditions[props.sortTypeFieldName] = state.sortSet[0].sortType
        }
        let list = []
        if (props.pager) {
            conditions.page = state.pager.page
            conditions.pageSize = state.pager.pageSize
            const res = await JBoltApi.tryGet(props.searchUrl, conditions)
            list = res.data?.list ?? []
            state.pager.totalRow = res.data?.totalRow
            state.tableStartIndex = (res.data.pageNumber - 1) * res.data.pageSize
        } else {
            const res = await JBoltApi.tryGet(props.searchUrl, conditions)
            list = res.data ?? []
        }
        console.log('list',list)
        emit('afterSearch', list)
        state.list = list
        nextTick(() => {
            emit('afterRender', state.list)
        })
    } finally {
        state.searching = false
    }
}

function doReset() {
    if (props?.searchConditions?._reset) {
        props.searchConditions._reset()
        loadData(true)
    } else {
        console.error(
            '没有找到_reset方法，请检查searchConditions属性是否使用useResetRef包裹'
        )
    }
}

onMounted(() => {
    if (props.searchUrl) {
        loadData()
    }
})

watch(()=>props.searchUrl, (newV)=>{
    if (newV) {
        loadData()
    }
})

/*    查询相关 end    */

/*    编辑相关 start    */
const editModalRef = ref(null)
const editModalStyle = computed(() => {
    return {
        width: props.editModalWidth
            ? isNaN(Number(props.editModalWidth))
                ? props.editModalWidth
                : `${props.editModalWidth}px`
            : '800px'
    }
})

/**
 * 编辑类型
 * @param title 弹出框的标题
 * @param editProps 编辑时要向组件传入 的props参数
 * @param modalArgs 弹出框的参数
 */
function showEditModal(title, editProps, modalArgs) {
    if (!props.editComponent) {
        console.error('未配置editComponent，不可调用此函数')
        return
    }
    console.debug(`打开编辑页面`, editProps)
    state.editModalShown = true
    state.editingProps = editProps ?? {}
    state.editModalArgs = Object.assign(modalArgs ?? {}, { title })
}

/**
 * 关闭编辑窗口
 */
function closeEditModal() {
    state.editModalShown = false
}

/**
 * 编辑弹窗点了提交按钮
 */
function doSubmit() {
    console.debug('EditComponent提交编辑', editModalRef.value)
    if (editModalRef.value) {
        if (state.isSubmiting) return
        if (!editModalRef.value.submit) {
            console.error(
                "EditComponent组件中未expose 'submit' 函数，无法处理按钮点击事件。注意：submit函数需要返回Promise<boolean>类型值"
            )
            return
        }
        state.isSubmiting = true
        editModalRef.value
            .submit()
            .then((data) => {
                closeEditModal()
                loadData()
                emit('afterSubmit', {
                    editingProps: state.editingProps,
                    result: data
                })
            })
            .finally(() => {
                state.isSubmiting = false
            })
    }
}

/**
 * 设置排序相关
 * @param sortField
 * @param sortType
 */
function setSort(sorts) {
    state.sortSet = sorts.filter((item) => !!item.sortType)
    loadData(true)
}

/*    编辑相关 end    */
defineExpose({
    state,
    loadData,
    showEditModal,
    closeEditModal,
    setSort
})

provide('currentPage', getCurrentInstance())
</script>

<template>
    <div class="h-full">
        <n-card :bordered="bordered" class="jb-crud-page h-full rounded-8px shadow-sm">
            <template v-if="props.headerShown" #header>
                <div class="flex items-center w-full overflow-hidden">
                    <div class="title_wrapper shrink-0 flex align--center">
                        <slot name="title">
                            <jb-icon :local="true"
                                v-if="props.titleIcon"
                                class="text-20px mt-3px"
                                :icon="props.titleIcon"
                            ></jb-icon>
                            <span v-if="props.titleText" class="ml-10px">
                                {{ props.titleText }}
                            </span>
                        </slot>
                    </div>

                    <div class="flex-1">
                        <n-space
                            align="center"
                            :wrap-item="true"
                            :justify="props.conditionsAlign"
                            class="conditions_wrapper ml-16px"
                            item-style="display: flex; align-items: center;"
                        >
                            <slot name="conditions">
                                <slot name="conditions-form"></slot>
                                <slot name="conditions-btn">
                                    <jb-btn
                                        v-if="props.searchBtnShown"
                                        :icon="Icons.SEARCH"
                                        :loading="state.searching"
                                        type="primary"
                                        ghost
                                        @click="loadData(true)"
                                        >查询</jb-btn
                                    >
                                    <jb-btn
                                        v-if="
                                            props.resetBtnShown && props.searchConditions
                                        "
                                        :icon="Icons.RESET"
                                        type="tertiary"
                                        @click="doReset"
                                        >重置</jb-btn
                                    >
                                </slot>
                            </slot>
                        </n-space>
                    </div>
                    <div class="opt_wrapper shrink-0 ml-24px flex align--center">
                        <slot name="opt"></slot>
                    </div>
                </div>
            </template>
            <n-spin v-if="state.searching" class="loading_panel"> </n-spin>
            <slot
                :table-start-index="state.tableStartIndex"
                :list="state.list"
                :pager="state.pager"
                :state="state"
            >
            </slot>
            <template #footer>
                <slot name="footer">
                    <div v-if="props.searchUrl && props.pager" class="flex justify-end">
                        <n-pagination
                            v-model:page="state.pager.page"
                            v-model:page-size="state.pager.pageSize"
                            :item-count="state.pager.totalRow"
                            show-size-picker
                            :page-sizes="pageSizeOptions"
                            :on-update-page="() => loadData(false)"
                            :on-update-page-size="() => loadData(false)"
                        >
                            <template #suffix> 共{{ state.pager.totalRow }}条 </template>
                        </n-pagination>
                    </div>
                </slot>
            </template>
        </n-card>

        <n-modal
            v-if="editComponent"
            :show="state.editModalShown"
            class="edit_dialog"
            preset="dialog"
            :style="editModalStyle"
            v-bind="state.editModalArgs"
            positive-text="提交"
            negative-text="关闭"
            :loading="state.isSubmiting"
            @negative-click="closeEditModal()"
            @positive-click="doSubmit()"
            @close="state.editModalShown = false"
        >
            <template #icon>
                <jb-icon :local="true"
                    v-if="state.editModalArgs.icon !== ''"
                    :icon="state.editModalArgs.icon ?? 'mdi:edit-box'"
                ></jb-icon>
                <span v-else class="icon__hide"></span>
            </template>
            <component
                :is="editComponent"
                ref="editModalRef"
                class="mt-24px"
                v-bind="state.editingProps"
                @success="loadData()"
            ></component>
        </n-modal>
    </div>
</template>

<style scoped lang="scss">
.dark .jb-crud-page .loading_panel {
    background: rgb(0, 0, 0, 0.56);
}
.title_wrapper {
    & > :deep(.iconify:first-child) {
        margin-top: 3px;
    }
}
.jb-crud-page {
    border-radius: 8px;
    .loading_panel {
        position: absolute;
        background: rgb(255, 255, 255, 0.56);
        z-index: 99;
        inset: 0;
    }
    :deep(.n-card-header) {
        flex-shrink: 0;
        padding-top: 16px;
        padding-bottom: 16px;
    }
    :deep(.n-card__footer) {
        flex-shrink: 0;
    }
    :deep(.n-card__content) {
        overflow: auto;
        display: flex;
        flex: 1;
        flex-direction: column;
        position: relative;
        padding-bottom: 16px;
    }
    :deep(.n-card-header__extra) {
        flex: 1;
    }
}
</style>
